﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DotSpatial.Data;
using DotSpatial.Topology;

namespace GeostatisticalTool.Classes
{
    public class DataSourceInterpolators
    {
        private int npoints1 = 0;
        private int np1 = 0;
        private double[,] cpoints1;
        private List<Kpoint> kpoints= new List<Kpoint>();
        private QuadTree quadTree1;
        private double[] extent1 = { double.MaxValue, double.MaxValue,double.MaxValue, double.MinValue, double.MinValue, double.MinValue  };//xmin ymin zmin xmax ymax zmin
        private long[] idExtremPoints;
        private long[] idExtremeZPoints;
        private double[] extentZ1 = { double.MaxValue, double.MinValue };//zmin zmax
        private IFeatureSet data;

        //public IFeatureSet Data
        //{
        //    get { return data; }
        //    set { data = value; }
        //}
        
        private SearchData search;


        public DataSourceInterpolators(IFeatureSet data, int idField)
        {
            this.CreatePointsK(data, idField);
            search = new SearchData(kpoints,quadTree1,extent1);
        }

        #region propierties

        public List<Kpoint> Kpoints
        {
            get { return kpoints; }
            set { kpoints = value; }
        }

        public SearchData Search
        {
            get { return search; }
            set { search = value; }
        }



        public double[] extent
        {
            get { return extent1; }
            set { extent1 = value; }
        }


        public double[] extentZ
        {
            get { return extentZ1; }
            set { extentZ1 = value; }
        }


        public QuadTree quadTree
        {
            get { return quadTree1; }
            set { quadTree1 = value; }
        }
        public double[,] cpoints
        {
            get { return cpoints1; }
            set { cpoints1 = value; }
        }


        /// <summary>Gets a value indicating number of point in the Shapefile</summary> 
        public int npoints
        {
            get { return this.npoints1; }
        }

        /// <summary>Gets a value indicating number of points used by search</summary> 
        public int np
        {
            get { return this.np1; }
            set { this.np1=value; }
        }

        #endregion 

        public SearchData GetSearch()
        {
            return this.search;
        }
        
        private void CreatePoints(
           IFeatureSet shapeLayer, int idField)
        {
            this.npoints1 = shapeLayer.NumRows();
            this.cpoints1 = new double[this.npoints1, 7];//x,y,z,z-inter,error,stderr
            this.quadTree1 = new QuadTree();

            for (int shp = 0; shp < shapeLayer.NumRows(); shp++)
            {
                Coordinate pt = shapeLayer.Features[shp].Coordinates[0];
                this.cpoints1[shp, 0] = pt.X;
                this.cpoints1[shp, 1] = pt.Y;
                this.cpoints1[shp, 6] = pt.Z;
                this.cpoints1[shp, 2] = Convert.ToDouble(shapeLayer.Features[shp].DataRow[idField]);
               // this.quadTree1.Insert(pt.X, pt.Y, shp);


                if (this.cpoints1[shp, 6] > this.extentZ1[1])
                {
                    this.extentZ1[1] = this.cpoints1[shp, 2];
                }

                if (this.cpoints1[shp, 2] > this.extentZ1[1])
                {
                    this.extentZ1[1] = this.cpoints1[shp, 2];
                }
                if (this.cpoints1[shp, 2] < this.extentZ1[0])
                {
                    this.extentZ1[0] = this.cpoints1[shp, 2];
                }
                //xmin ymin xmax ymax
                //xmin ymin zmin xmax ymax zmax
                if (pt.Z > this.extent1[5])
                {
                    this.extent1[5] = pt.Z;
                }

                if (pt.Y > this.extent1[4])
                {
                    this.extent1[4] = pt.Y;
                }

                if (pt.X > this.extent1[3])
                {
                    this.extent1[3] = pt.X;
                }

                if (pt.X < this.extent1[0])
                {
                    this.extent1[0] = pt.X;
                }

                if (pt.Y < this.extent1[1])
                {
                    this.extent1[1] = pt.Y;
                }
            }
            

        }

        int LIMIT = 5000;
        public List<int> SelectRandom(int count)
        {
            List<int> listn = new List<int>();
            if (count < LIMIT)
            {
                for (int i = 1; i <= LIMIT; i++)
                    listn.Add(i);

                return listn;
            }

          
            List<int> available = new List<int>(count);
            for (int i = 1; i <= count; i++)
                available.Add(i);



            List<int> result = new List<int>();
            Random random = new Random();
            while (available.Count > 0 && listn.Count < LIMIT)
            {
                int index = random.Next(available.Count);
                listn.Add(available[index]);
                available.RemoveAt(index);
            }



            return listn;



        }


        private void CreatePointsK(
          IFeatureSet shapeLayer, int idField)
        {
            this.data = shapeLayer;
            this.npoints1 = shapeLayer.NumRows();
           // this.kpoints = new Kpoint[this.npoints1];//x,y,z,z-inter,error,stderr
            this.quadTree1 = new QuadTree();
            Stat NorthSouth = new Stat(false);
            Stat EastWest = new Stat(false); 
            Stat TopBott = new Stat(false);
            Stat Zvalue = new Stat(false);
            List<int> l = SelectRandom(shapeLayer.NumRows());
            this.npoints1 = l.Count();

            for (int shp1 = 0; shp1 < l.Count; shp1++)
            {
                int shp = l[shp1];
                Coordinate pt = shapeLayer.Features[shp].Coordinates[0];
                Kpoint point = new Kpoint(pt.X, pt.Y, pt.Z, Convert.ToDouble(shapeLayer.Features[shp].DataRow[idField]), shp);
                this.kpoints.Add(point );
                //this.cpoints1[shp, 0] = pt.X;
                //this.cpoints1[shp, 1] = pt.Y;
                //this.cpoints1[shp, 2] = Convert.ToDouble(shapeLayer.Features[shp].DataRow[idField]);
                this.quadTree1.Insert(pt.X, pt.Y, point);
                NorthSouth += new Stat(pt.Y);
                EastWest += new Stat(pt.X);
                TopBott += new Stat(pt.Z);
                Zvalue +=  new Stat(point.W);
            }
                this.extentZ1= new  double[2] {Zvalue.Min,Zvalue.Max};
                this.extent1= new  double[6]{EastWest.Min,NorthSouth.Min,TopBott.Min,EastWest.Max,NorthSouth.Max, TopBott.Max};
                this.idExtremPoints= new long[6]{EastWest.PosMin,NorthSouth.PosMin,TopBott.PosMin,EastWest.PosMax,NorthSouth.PosMax, TopBott.PosMax};
                this.idExtremeZPoints= new long[2]{Zvalue.PosMin,Zvalue.PosMax};
        }

    }
}
